var GoogleSuggest = GownFullModule.extend({
	ime: null,
	current_list: null,
	current_query: null,
	last_list: null,
	last_query: null,
	target_list: 'ShiftQWERT',
	constructor: function()
	{
		var y = this;

		this._googlesuggest_functional = function(x) {
			if(x instanceof Function) {
				var dxchg = x();

				if(dxchg && !dxchg.htmlp) y.GenerateSuggest(dxchg.value);
				return x;
			}
			else return x;
		}
		this._keyboard_observer = function(obj,type,key,modifiers,b)
		{
			if(!b) return false;
			if(type == Const.KEY_TYPE_PRESS) y.StopSuggest();
			return true;
		};
	},
	module_name: function()
	{
		return 'GoogleSuggest';
	},
	init_module: function(ime,modman)
	{
		var b;

		this.ime = ime; // store reference to IME for further use.
		
		// register a GoogleSuggest functional
		b = GFFunctionalInterpreter.RegisterFunctional('googlesuggest',this._googlesuggest_functional);
		if(!b) {
			Debug.present && Debug.trace(0,'GoogleSuggest: Error, functional :googlesuggest is already registered.');
			return false;
		}
		this.ime.AddKeyboardObserver(this._keyboard_observer);
		return true;
	},
	cleanup_module: function()
	{
		this.ime.RemoveKeyboardObserver(this._keyboard_observer);
		// unregister GoogleSuggest functional
		GFFunctionalInterpreter.UnregisterFunctional('googlesuggest');
		// and cancel all loading suggest..
		this.StopSuggest();
		return true;
	},
	GenerateSuggest: function(str)
	{
		var nurl;

		this.StopSuggest();
		// Pretend we are in google suggest home page...
		if(!window.google) window.google = {};
		if(!window.google.ac) window.google.ac = {};
		
		window.google.ac.Suggest_apply = function(d1,query,list) {
			var ret = {},i;

			if(!list) ret.list = null;
			else {
				ret.list = new Array();
				for(i=1;i<list.length && ret.list.length < 9;i+=2) {
					if(list[i] && list[i].length > 0) ret.list.push(list[i]);
				}
			}
			ret.query = query;
			DownloadManager.ServerCallbackName('GoogleSuggest_Callback',ret);
		}

		url = 'http://www.google.com/complete/search?hl=en&client=suggest&js=true&q=' + encodeURI(str);
		DownloadManager.NewDownloadName('GoogleSuggest_Callback',url,function(userdata,serverdata) { userdata.SuggestCallback(serverdata); },this,true);
	},
	SuggestCallback: function(ret)
	{
		var x = this;
		var candlist;

		if(!ret.list || ret.list.length == 0) {
			this.ime.candwin.ReleaseList(this,this.target_list);
			this.ime.candwin.UpdateCandidate();
		}
		else {
			this.current_list = ret.list;
			this.current_query = ret.query;
			// scan for last list...
			if(this.last_query) {
				var len,i,str,tmplist;

				tmplist = new Array();
				len = lib.utf16charlen(this.last_query);
				for(i=0;i<this.last_list.length;i++) {
					// remove the first part of the current list...
					str = this.last_list[i].substr(len);
					// filter the list that does not match the current query...
					if(str.substr(0,this.current_query.length) == this.current_query && lib.utf16charlen(str) != str.length) {
						tmplist.push(str);
						this.current_list.push(str);
					}
				}
				this.current_list = tmplist.concat(this.current_list);
			}
			this.last_list = this.current_list;
			this.last_query = this.current_query;

			Debug.present && Debug.trace(1,'GoogleSuggest: data=(%s)',ret.list);
			candlist = this.ime.candwin.OccupyList(this,this.target_list);
			if(candlist) {
				candlist.SetList(null,this.current_list,function(obj,pos) { return x.SuggestHandler(obj,pos); });
				this.ime.candwin.UpdateCandidate();
			}
			else {
				Debug.present && Debug.trace(1,'GoogleSuggest: %s is occupied.',this.target_list);
			}
		}
	},
	SuggestHandler: function(obj,pos)
	{
		var str;

		str = this.current_list[pos];
		str = str.replace(new RegExp('^' + this.current_query),'');
		this.ime._SendString(obj,str,true);
		return true;
	},
	StopSuggest: function()
	{
		DownloadManager.CancelDownloadName('GoogleSuggest_Callback');
		this.ime.candwin.ReleaseList(this,this.target_list);
		this.ime.candwin.UpdateCandidate();
	}
});

